<template>
    <div class="index" v-loading="isLoading">
        <div class="model-title">Model:
            机器狗
        </div>
        <div class="chat_container" ref="chat_container_box">
            <div class="chat_t" v-if="false">
                <span>机器狗</span>
                <span> </span>
            </div>
            <div class="chat_warp" v-resize="onResize" ref="chat_container"></div>
        </div>
        <div class="footer">
            <el-input v-model="chatText" @keydown.enter="messageTo($event)"
                      autosize
                      type="textarea"
                      placeholder="请输入你需要问的问题"
            >
            </el-input>
            <div class="suffix">
                <div @click="messageTo" v-if="!time">
                    <el-icon class="icon-input" :size="20">
                        <Position/>
                    </el-icon>
                </div>
                <div v-else @click="stopMessage">
                  <el-tooltip
                      effect="dark"
                      content="点击可以快速取消当前话哦"
                      placement="top"
                  >
                    <el-icon class="icon-input" :size="20">
                      <Clock/>
                    </el-icon>
                  </el-tooltip>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import {watch, ref, computed, onMounted, onUnmounted,nextTick} from 'vue'
import {useRouter, useRoute, onBeforeRouteUpdate} from 'vue-router'
import {ElMessage} from 'element-plus';
import {Position} from '@element-plus/icons-vue'
import MarkdownIt from 'markdown-it'
import mdKatex from '@traptitech/markdown-it-katex'
import hljs from 'highlight.js'
import {Prompts} from '@/components'
import {chatStart, chatDetail} from "@/api/chat";
import {useStore} from "@/pinia";
import wenTou from '@/assets/personal.png'
import wenDa from '@/assets/da.png'
import {chunkArray} from '@/lib/chunkArray'
import {clearPending,getToken} from "@/axios";

const router = useRouter()
const store = useStore()
const {addHistoryRouter} = store
let chatText = ref<string>('')
let parentUid = ref<string>('')
let chatMsg = ref<string>('')
let chat_container = ref<HTMLDivElement>()
let chat_container_box = ref<HTMLDivElement>()
let isAddRouter = computed(() => store.isAddRouter)
let isLoading = ref<boolean>(false)
// let isModel = ref<boolean>(false)
let isHistory = computed(() => store.isHistory)
let time = ref<any>()
let promptCode = computed(() => store.promptCode)
let promptName = computed(() => store.promptName)

const mdi = new MarkdownIt({
  linkify: true,
  highlight(code, language) {
    const validLang = !!(language && hljs.getLanguage(language))
    if (validLang) {
      const lang = language ?? ''
      return highlightBlock(hljs.highlight(lang, code, true).value, lang)
    }
    return highlightBlock(hljs.highlightAuto(code).value, '')
  },
})

mdi.use(mdKatex, {blockClass: 'katexmath-block rounded-md p-[10px]', errorColor: ' #cc0000'})


const text = computed(() => {
  return mdi.render(chatMsg.value)
})

function highlightBlock(str: string, lang?: string) {
  return `<pre class="code-block-wrapper"><div class="code-block-header"><span class="code-block-header__lang">${lang}</span><span class="code-block-header__copy">${lang}</span></div><code class="hljs code-block-body ${lang}">${str}</code></pre>`
}

//中断message
let controller = new AbortController();
let signal = controller.signal;
const stopMessage = () => {
  time.value = false
  controller.abort();
  controller = new AbortController();
  signal = controller.signal
  clearPending()
}

let meta = ''
const messageTo = async (e: Event | any) => {
  e.preventDefault();
  if (e.type === 'click') {
    if (!chatText.value) {
      return false
    }
  } else if (e.type === 'keydown') {
    if (e.keyCode !== 13) {
      return false
    }
  }
  if(!chatText.value.trim()) {
    return false
  }

  if (time.value) {
    return false
  }
  time.value = '你可以执行拉'
  meta = chatText.value
  let pending = `<div class="pending"></div>`
  let markDown = createMessageList(chatText.value, pending,false)
   let params = {
       "model": "gpt-3.5-turbo",
       "messages": [
           {
               "role": "user",
               "content": chatText.value
           }
       ],
       "stream": true
   }

  chatText.value = ''
  chatMsg.value = ''

  fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    body: JSON.stringify(params),
    signal: signal,
    headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${getToken()}`
    }
  })
    .then(response => {
      if(response.status !== 200) {
        console.error(response)
        markDown.innerHTML = `<span style="color: red">服务器正在经历中年危机。它将在短暂的自我探索之旅后尽快回来。尝试刷新一下哦！</span>`
        time.value = false
        return;
      }
      const reader = response.body?.getReader();
      const decoder = new TextDecoder('utf-8');
      console.log('**--**', response)
      reader?.read().then(async function processResult(result, preChunk?: string): Promise<void> {
        if (result.done) {
          time.value = false;
          //回答完毕之后,调一下历史接口,新增一条记录
            console.log(111)
          return;
        }
        let nextPreCHunk = '';
        let chunk = decoder.decode(result.value, {stream: true});
          // return
          // console.log(chunk)
        let saying = chunk.split('\n\n').filter(v => !!v).map(v => v.replace(/^data: /, '')).filter(v => !!v)
          // console.log(saying)
        // let saying = chunk.split('\n').filter(v => !!v).join('').replace(/data:/g, 'xym').split('xym').filter(v => !!v)
        if (saying && saying.length > 0) {
          let say = saying.map(item => {
            let content = '';
            try {
              const jsonItem = JSON.parse(item);

              (jsonItem.choices[0]).delta.content && (content = (jsonItem.choices[0]).delta.content)
              jsonItem.uid && (parentUid.value = jsonItem.id)

            } catch {
              console.error('解析 chunk 出错了', chunk)
              content = ''
            }
            return content
          }).reduce((x,y) => x+y)
          chatMsg.value += say
          markDown.innerHTML = text.value
        }

        return reader.read().then((nextRes) => processResult(nextRes, nextPreCHunk));
      });
    })
    .catch(error => {
      console.error(error)
      markDown.innerHTML = `<span style="color: red">服务器正在经历中年危机。它将在短暂的自我探索之旅后尽快回来。尝试刷新一下哦！</span>`
      time.value = false
    });

}
//这个函数是 点击切换到历史,获取历史内容的
const getChatDetails = async (uid: string) => {
  const result = await chatDetail({uid: uid})
  if (result.isSuccess) {
    isLoading.value = false
    let {data} = result
    //这里获取最后一个uid 用于开启新的对话
    parentUid.value = (data[data.length - 1]).uid
    if (data.length > 2) {
      let chunkArr = chunkArray(data, 2)
      chunkArr.forEach((item) => {
        createMessageList(item[0].text, item[1].text)
      })
    } else {
      createMessageList(data[0].text, data[1].text)
    }

  }
}
// create 用于聊天的页面元素
const createMessageList = (userMsg: string, aiMsg: string,isMark:boolean = true) => {
  let wen = document.createElement('div')
  let wenIms = document.createElement('img')
  let wenSp = document.createElement('span')
  wenIms.setAttribute('src', wenTou)
  wenIms.setAttribute('width', '30px')
  wenIms.style.marginRight = '10px'
  wen.className = 'chat_wen'

  wenSp.innerText = userMsg
  wen.append(wenIms)
  wen.append(wenSp)
  let da = document.createElement('div')
  da.className = 'chat_da'
  let markDown = document.createElement('div')
  let svgImg = document.createElement('img')
  svgImg.className = 'svg-img'
  svgImg.src = wenDa
  markDown.className = 'markdown-body'
  markDown.style.width = '100%'
  markDown.innerHTML = isMark?mdi.render(aiMsg):aiMsg
  da.append(svgImg)
  da.append(markDown)
  chat_container.value!.append(wen)
  chat_container.value!.append(da)
  return markDown
}
onMounted(async () => {
  //用户第一次进入的时候,模块没有加载,这里需要做个判断

})
onUnmounted(() => {
  let params = router.currentRoute.value.params
  params.username = ''
})
const getContainerHeight = () => {
  let chatContainerHeight = ref<number>((chat_container.value as HTMLDivElement)?.offsetHeight);
  return chatContainerHeight.value
}
const getContainerBoxHeight = () => {
  let chatContainerHeight = ref<number>((chat_container_box.value as HTMLDivElement)?.offsetHeight);
  return chatContainerHeight.value
}

const onResize = () => {
  chat_container_box.value!.scrollTop = (getContainerHeight() - getContainerBoxHeight() + 20)
}
</script>

<style scoped lang="scss">
:deep(textarea) {
	resize: none;
  padding-right: 40px;
}
.index {
  //background: rgb(247, 247, 248);
  //background: #fff;
  //height: 100%;
  width: 100%;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  //grid-template-rows: calc(100vh - 80px);
  padding: 40px 0 20px;
  //height: calc(100vh - 80px);
    height: 100%;
  justify-content: space-between;
}

.model-title {
  position: absolute;
  width: 100%;
  color: var(--text-color-title);
  padding: 12px;
  background: var(--bg-color-title);
  top: 0;
  left: 0;
  font-size: 16px;
  box-sizing: border-box;
}
:deep(.code-block-wrapper) {
  width: 100%;
  >pre {
    width: 100%!important;
  }
}
.footer {
  //flex-grow: .08;
  background: var(--bg-color-wen);
  //padding: 13px 37px 13px 57px;
  //height: 0;
  width: 85%;
  //margin: auto;
  //box-shadow: 0 0 10px 0 rgba(0, 0, 0, .1);
  position: relative;
  padding: 15px 10px 0;
  border-radius: 5px;
  //height: 0;
  //flex-grow: 1;
  font-size: 0;
}
:deep(.el-textarea) {
  box-shadow: 0 0 0 1px var(--bg-border-input, var(--bg-color-da));
  border-radius: 5px;
  background: var(--bg-input-color);
  padding: 10px 0;
}
.suffix {
  cursor: pointer;
  position: absolute;
  font-size: 0;
  right: 20px;
  top: 32px;
  //transform: translateY(-50%);
}

.chat_container {
  text-align: left;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  padding-bottom: 20px;
  flex: 1;
  width: 100%;
  //height: 0;
  //flex-grow: 10;
  //flex-grow: 1;
  //height: 0;
  &::-webkit-scrollbar {
    background-color: transparent;
    -webkit-border-radius: 2em;
    -moz-border-radius: 2em;
    border-radius: 2em;
    width: 0;
  }

  &::-webkit-scrollbar-thumb {
    background-color: transparent;
    -webkit-border-radius: 2em;
    -moz-border-radius: 2em;
    border-radius: 2em;
  }
}

:deep(.chat_da) {
  //background: #fff;
  padding: 30px;
  line-height: 27px;
  background: var(--bg-color-da);
  color: var(--text-color-da);
  font-size: 16px;
  display: flex;
  align-items: flex-start;
}

:deep(.svg-img) {
  //background: rgb(16, 163, 127);
  color: #fff;
  flex: 0 0 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  margin-right: 10px;
}

:deep(.chat_wen) {
  padding: 30px;
  line-height: 27px;
  display: flex;
  align-items: center;
  color: var(--text-color-da);
  font-size: 16px;
}

.icon-input {
  color: var(--text-color-da);
}

.chat_t {
  display: flex;
  align-items: center;
  margin: auto;

  span {
    &:nth-child(1) {
      font-size: 36px;
      color: #d9d9e2;
      font-weight: bold;
    }

    &:last-child {
      background: rgb(250, 230, 158);
      color: rgb(146, 114, 1);
      font-size: 14px;
      font-weight: bold;
      padding: 2px 6px;
      border-radius: 6px;
      margin-left: 6px;
    }
  }
}

:deep(.el-textarea__inner) {
  background: var(--bg-input-color);
  box-shadow: none;
  //padding-top: 9px;
  //box-shadow: 0 0 0 1px var(--bg-border-input, var(--bg-color-da));

}

:deep(.el-textarea__inner) {
  color: var(--text-color-da);

}


:deep(.pending) {
  width: 10px;
  height: 20px;
  background: #000;
  animation: peddings 0.5s linear infinite forwards;
}

@keyframes peddings {
  to {
    opacity: 1;
  }
  from {
    opacity: 0;
  }
}

#anchor {
  height: 1px;
  overflow-anchor: auto;
}
</style>
